#include "valor.h"

Valor::Valor()
{
    tipo = VALOR_NULO;
}

Valor::Valor(bool booleano) : variant(booleano)
{
    tipo = VALOR_BOOLEANO;
}

Valor::Valor(int entero) : variant(entero)
{
    tipo = VALOR_ENTERO;
}

Valor::Valor(long long entero) : variant(entero)
{
    tipo = VALOR_ENTERO;
}

Valor::Valor(double real) : variant(real)
{
    tipo = VALOR_REAL;
}

Valor::Valor(const QString& cadena) : variant(cadena)
{
    tipo = VALOR_CADENA;  
}

Valor::Valor(const QVariant& variant)
{
    this->variant = variant;
    switch (variant.type()) {
        case QVariant::Bool:
            tipo = VALOR_BOOLEANO;
            break;
        case QVariant::Int:
        case QVariant::UInt:
        case QVariant::LongLong:
        case QVariant::ULongLong:
        case QVariant::Char:
            tipo = VALOR_ENTERO;
            break;
        case QVariant::Double:
            tipo = VALOR_REAL;
            break;
        case QVariant::String:
            tipo = VALOR_CADENA;
            break;
        default:
            tipo = VALOR_NULO;
    }
}


Valor::~Valor()
{

}

#define hay(TIPO) ( tipo == (TIPO) || otroValor.tipo == (TIPO) )
#define operar(TYPE, OP) ( Valor(variant.value<TYPE>() OP otroValor.variant.value<TYPE>()) )

Valor Valor::operator+(const Valor& otroValor) const
{
    if (hay(VALOR_CADENA)) {
        return operar(QString, +);
    }

    if (hay(VALOR_REAL)) {
        return operar(double, +);
    }

    if (hay(VALOR_ENTERO) || hay(VALOR_BOOLEANO)) {
        return operar(long long, +);
    }

    return Valor();
}

Valor Valor::operator-(const Valor& otroValor) const
{
    if (hay(VALOR_REAL)) {
        return operar(double, -);
    }

    if (hay(VALOR_ENTERO) || hay(VALOR_BOOLEANO)) {
        return operar(long long, -);
    }

    if (hay(VALOR_CADENA)) {
        return operar(double, -);
    }

    return Valor();
}

Valor Valor::operator*(const Valor& otroValor) const
{
    if (hay(VALOR_REAL)) {
        return operar(double, *);
    }

    if (hay(VALOR_ENTERO) || hay(VALOR_BOOLEANO)) {
        return operar(long long, *);
    }

    if (hay(VALOR_CADENA)) {
        return operar(double, *);
    }

    return Valor();
}

Valor Valor::operator/(const Valor& otroValor) const
{
    if (hay(VALOR_REAL) || hay(VALOR_ENTERO) || hay(VALOR_BOOLEANO) || hay(VALOR_CADENA)) {
        return operar(double, /);
    }

    return Valor();
}

Valor Valor::operator-() const
{
    Valor otroValor;

    if (hay(VALOR_REAL)) {
        return - Valor(variant.value<double>());
    }

    if (hay(VALOR_ENTERO) || hay(VALOR_BOOLEANO)) {
        return - Valor(variant.value<long long>());
    }

    if (hay(VALOR_CADENA)) {
        return - Valor(variant.value<double>());
    }

    return Valor();
}

Valor Valor::operator<(const Valor& otroValor) const
{
    if (hay(VALOR_CADENA)) {
        return operar(QString, <);
    }

    if (hay(VALOR_REAL)) {
        return operar(double, <);
    }

    if (hay(VALOR_ENTERO) || hay(VALOR_BOOLEANO)) {
        return operar(long long, <);
    }

    return Valor();
}

Valor Valor::operator<=(const Valor& otroValor) const
{
    if (hay(VALOR_CADENA)) {
        return operar(QString, <=);
    }

    if (hay(VALOR_REAL)) {
        return operar(double, <=);
    }

    if (hay(VALOR_ENTERO) || hay(VALOR_BOOLEANO)) {
        return operar(long long, <=);
    }

    return Valor();
}


Valor Valor::operator>(const Valor& otroValor) const
{
    if (hay(VALOR_CADENA)) {
        return operar(QString, >);
    }

    if (hay(VALOR_REAL)) {
        return operar(double, >);
    }

    if (hay(VALOR_ENTERO) || hay(VALOR_BOOLEANO)) {
        return operar(long long, >);
    }

    return Valor();
}

Valor Valor::operator>=(const Valor& otroValor) const
{
    if (hay(VALOR_CADENA)) {
        return operar(QString, >=);
    }

    if (hay(VALOR_REAL)) {
        return operar(double, >=);
    }

    if (hay(VALOR_ENTERO) || hay(VALOR_BOOLEANO)) {
        return operar(long long, >=);
    }

    return Valor();
}

Valor Valor::operator==(const Valor& otroValor) const
{
    if (hay(VALOR_CADENA)) {
        return operar(QString, ==);
    }

    if (hay(VALOR_REAL)) {
        return operar(double, ==);
    }

    if (hay(VALOR_ENTERO) || hay(VALOR_BOOLEANO)) {
        return operar(long long, ==);
    }

    return Valor();
}

Valor Valor::operator!=(const Valor& otroValor) const
{
    if (hay(VALOR_CADENA)) {
        return operar(QString, !=);
    }

    if (hay(VALOR_REAL)) {
        return operar(double, !=);
    }

    if (hay(VALOR_ENTERO) || hay(VALOR_BOOLEANO)) {
        return operar(long long, !=);
    }

    return Valor();
}

Valor Valor::operator&&(const Valor& otroValor) const
{
    if (hay(VALOR_NULO)) {
        return Valor();
    }

    return operar(bool, &&);
}

Valor Valor::operator||(const Valor& otroValor) const
{
    if (hay(VALOR_NULO)) {
        return Valor();
    }

    return operar(bool, ||);
}

void Valor::setTipo(int tipo)
{
    this->tipo = tipo;
    switch (tipo) {
    case VALOR_NULO:
        variant.convert(QVariant::Invalid);
        break;
    case VALOR_BOOLEANO:
        variant.convert(QVariant::Bool);
        break;
    case VALOR_ENTERO:
        variant.convert(QVariant::Int);
        break;
    case VALOR_REAL:
        variant.convert(QVariant::Double);
        break;
    case VALOR_CADENA:
        variant.convert(QVariant::String);
        break;
    default:
        break;
    }  
}

int Valor::getTipo()
{
    return tipo;
}